<template>
  <h1>App</h1>
  <button @click="flag = !flag">change</button>
  <input type="text" v-model="value">
  <!-- 使用自定义指令时，采用v-Name的形式，:参数.修饰符=值 -->
  <!-- 更新 -->
  <Child v-Name:aaa="{ backgroundColor: 'green', flag }"></Child>
  <!-- 卸载 -->
  <Child v-if="flag" v-Name:aaa="{ backgroundColor: 'green' }"></Child>
  <Child v-move="{backgroundColor: value}"></Child>
</template>
<script setup lang="ts">

// 自定义指令：函数形式或对象形式，在自定义指令中使用生命周期钩子函数用于实现功能
// 函数形式 const vName = () => {} 默认会触发 mounted 和 updated
// 对象形式: 在对象内部定义各个生命周期函数实现功能，生命周期指自定义指令绑定的元素的生命周期
// const vName:Directive = () => {
//   自定义指令绑定的元素创建后
//   生命周期钩子函数接受参数
//   created(...arg:Array<any>) {
//     arg[0]:HTMLElement 绑定的元素
//     该泛型约束的是 value 属性
//     arg[1]:DirectiveBinding<Dir> {arg,value,oldValue,modifiers,instance}
//     arg[2] 组件的 vnode 虚拟 DOM 对象
//     arg[3] 组件的前一个虚拟 DOM 对象
//   },
//   自定义指令绑定的元素渲染到页面前
//   beforeMount() {},
//   自定义指令绑定的元素渲染到页面后
//   mounted() {},
//   自定义指令绑定的元素更新前
//   beforeUpdate() {},
//   自定义指令绑定的元素更新后
//   updated() {},
//   自定义指令绑定的元素卸载前
//   beforeUnmount() {},
//   自定义指令绑定的元素卸载后
//   unmounted() {}
// }


// 导入子组件
import { Directive, DirectiveBinding, ref } from 'vue'
import Child from './Child.vue'
// 定义类型约束 DirectiveBinding.value
interface T {
    backgroundColor:string
}
// 定义 flag 用于切换子组件显示(卸载)或改变组件的值(更新)
const flag = ref<boolean>(true)
// 定义 value 用于存储背景颜色修改值
const value = ref<string>('')

// 定义自定义指令,自定义指令实质为包含自定义指令生命周期钩子函数的对象,类型为 Directive
const vName: Directive = {
  // 自定义指令的生命周期实质为绑定指令的元素的生命周期，从元素创建后到卸载后
  // 生命周期函数可以接受一组参数以获取绑定元素的信息
  // 指令绑定的元素创建后
  created() {
    console.log('created')
  },
  // 指令绑定的元素插入到页面前
  beforeMount(...arg: Array<any>) {
    // 生命周期函数接受html中绑定指令时操作作为参数
    // 参数1：绑定指令的元素本身
    // 参数2：dir 对象，类型为 DirectiveBinding 为绑定指令时的操作，可以使用泛型进一步约束其 value 属性
    // 包含 arg instance 组件实例 modifiers oldValue value
    // 参数3：当前组件的虚拟 DOM Vnode 对象
    // 参数4：上一个虚拟 DOM 即 preVnode
    console.log(arg)
    console.log('beforeMount')
  },
  // 指令绑定的元素插入到页面后
  mounted(el:HTMLElement,dir:DirectiveBinding<T>) {
    el.style.backgroundColor = dir.value.backgroundColor
    console.log('mounted')
  },
  // 指令绑定的元素更新前
  beforeUpdate() {
    console.log('beforeUpdate')
  },
  // 指令绑定的元素更新后
  updated() {
    console.log('updated')
  },
  // 指令绑定的元素卸载前
  beforeUnmount() {
    console.log('beforeUnmount')
  },
  // 指令绑定的元素卸载后
  unmounted() {
    console.log('unmounted')
  },
}
// 自定义指令函数简写，即以函数的形式定义自定义指令
// 函数形式的自定义指令仅包含 mounted 和 updated 钩子
const vMove = (el:HTMLElement, dir:DirectiveBinding<T>) => {
  el.style.backgroundColor = dir.value.backgroundColor
}
</script>
<style lang="less" scoped></style>
